# -*- mode: python; coding: utf-8; -*-
##---------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##---------------------------------------------------------------------------##
"""
Info dialogs for games and stats debug for tile/tk.
"""
__docformat__ = "restructuredtext en"
#_ = lambda x: x

import ttk
import tkSimpleDialog
import tkFont

from . import constants as vcnst
from .widget import ScrolledTextFrame
from ..packlib import group as CSG
from ..gamelib import group as GI
from ..utillib.misc import format_time
from ..settings import CONF_OPT
from ..statform import LogFormatter
from ..utillib.pathdb import NJ_PATH


class _InfoDialog(tkSimpleDialog.Dialog):
    """
    Abstract deatils dialog.

    Creates blocks of key / value label pairs from field data within the
    dialog. Pairings are stored internal for later updates which are dynamic
    to show only pairs with value data when **update** is called.
    """
    __labels = {}
    _title = None

    def __init__(self, parent, **kwargs):
        """
        __init__(parent:Canvas[, game:Game | image:Image) -> None

        Augment to set passed object for Stats and Game this would be **Game**
        and for Cardset this would be **Images**.
        """
        assert len(kwargs) == 1 and kwargs in ['game', 'images']
        if 'game' in kwargs:
            self._object = kwargs['game']
        elif 'images' in kwargs:
            self._object = kwargs['images']
        tkSimpleDialog.Dialog.__init__(self, parent, self._title)

    def body(self, parent):
        """
        body(parent:Canvas) -> None

        Stub for subclass creation of dialog body.
        """
        raise NotImplementedError

    def buttonbox(self):
        """
        buttonbox() -> None

        Create an ok button for the dialog that calls parent **ok** method.
        """
        box = ttk.Frame(self)

        widget = ttk.Button(box, text=_('OK'), width=10, command=self.ok,
                            default=vcnst.ACTIVE)
        widget.pack(side=vcnst.LEFT, padx=4, pady=4)

        self.bind('<Return>', self.ok)
        self.bind('<Escape>', self.ok)

        box.pack()

    def _create_label_col(self, parent, title, fields, row):
        """
        _label_row(parent:Canvas, column:int, title:str,
          fields:seq(seq(str, str) ...), width:int) -> None

        Create a frame with **title** and **fields** as its row labels.
        """
        iframe = ttk.LabelFrame(parent, text=title)
        iframe.grid(row=row, column=0, padx=4, pady=4, ipadx=4, ipady=4,
                    sticky='nws')

        for row, (key, title) in enumerate(fields):
            title_label = ttk.Label(iframe, text='{}:'.format(title),
                                    justify='left', anchor='w')
            title_label.grid(row=row, column=0, sticky='nw', padx=4)
            text_label = ttk.Label(iframe, justify='left', anchor='w')
            text_label.grid(row=row, column=1, sticky='nw', padx=4)
            self.__labels[key] = (title_label, text_label)

    def update_label_col(self, fields):
        """
        _update_label_col(fields) -> None

        Update the frame's labels with **fields** data. Label pairs are hidden
        when its value is **None**.
        """
        for key, value in fields:
            title_label, text_label = self.__labels[key]
            if value in ('', None):
                title_label.grid_remove()
                text_label.grid_remove()
            else:
                title_label.grid()
                text_label.grid()
            text_label.config(text=value)


class GameInfoDialog(_InfoDialog):
    """
    Game deatils frame.

    Creates blocks of key / value label pairs from field data within a frame.
    Pairings are stored internal for later updates which are dynamic to show
    only pairs with value data when **update** is called.
    """
    _title = _('Game Info')

    def body(self, parent):
        """
        body(parent:Canvas) -> None

        Create blocks of label pairs for specific game and stack details.
        """
        fields = (('name', _('Name'),),
                  ('shortname', _('Short name'),),
                  ('altnames', _('Alternate names'),),
                  ('category', _('Category'),),
                  ('type', _('Type'),),
                  ('skill', _('Skill level'),),)
        self._create_label_col(parent, _('Game Info'), fields, row=0)

        fields = (('decks', _('Decks'),),
                  ('cards', _('Cards'),),
                  ('redeals', _('Redeals'),),)
        self._create_label_col(parent, _('Card Info'), fields, row=1)

        fields = (('module', _('Module'),),
                  ('class', _('Class'),),
                  ('gameid', _('ID')),
                  ('version', _('Version'),),
                  ('rules', _('Rules'),),
                  ('hint', _('Hint'),),)
        self._create_label_col(parent, _('Game Debug'), fields, row=2)

        fields = (('talon', _('Talon'),),
                  ('talon', _('Waste'),),
                  ('foundation', _('Foundations'),),
                  ('row', _('Rows:'),),
                  ('reserve', _('Reserves'),),
                  ('xwaste', _('X-Wastes'),),
                  ('braid',  _('Braid'),),)
        self._create_label_col(parent, _('Stack Debug'), fields, row=3)

        self.update_label_data()

    def update_label_data(self):
        """
        _update_label_data(self) -> None

        Call **self.update_label_cols** with values of game and stack details.
        """
        game = self._object

        def stack_info(stacks):
            """
            stack_info(stacks:seq(Stack ..)) -> None

            Gather stack details for label value with its name and count.
            """
            stack_class = {}
            for pile in stacks:
                name = pile.__class__.__name__
                if name in stack_class:
                    pile[name] += 1
                else:
                    pile[name] = 1
            return '\n'.join(['{0[0]} ({0[1]})'.format(i)
                                  for i in stack_class.items()])

        fields = [('name', game['name'],),
                  ('shortname', game['short_name'],)
                  ('altnames', '\n'.join(game['altnames']),),
                  ('gameid', game['id'],),
                  ('version', game['si']['version'],)
                  ('category', _(CSG.TYPE[game['category']])),
                  ('type', [s[0] for s in GI.GAMES_BY_TYPE if s[1](lgi)][0]),
                  ('skill', [s[0] for s in GI.GAMES_BY_SKILL if s[1](lgi)][0]),
                  ('decks', game['decks']),
                  ('cards', game['ncards']),
                  ('redeals', {-2:  _('variable'), -1: _('unlimited')
                              }.get(game['redeals'], str(game['redeals']))),
                  ('rules', game['rules_filename'],)
                  ('module', _('Module:'), game['gameclass'][0]),
                  ('class', _('Class:'), game['gameclass'][0]),
                  ('hint', _('Hint:'), game._hint_.__class__.__name__
                                           if game._hint_ else None), ]

        stack = game.s
        for name, pile in (('talon', [stack.talon],),
                           ('waste', stack.wastes,),
                           ('foundation', stack.foundations,),
                           ('row', stack.rows,),
                           ('reserve', stack.reserves,),
                           ('braid',  stack.braid,),):
            if pile:
                fields.append((name, stack_info(pile),))

        self.update_label_col(fields)


class StatsInfoDialog(_InfoDialog):
    """
    Stat deatils dialog.

    Creates blocks of key / value label pairs from field data within a frame.
    Pairings are stored internal for later updates which are dynamic to show
    only pairs with value data when **update** is called.
    """
    _title = _('Stat Info')

    def body(self, parent):
        """
        body(parent:Canvas) -> None

        Create blocks of label pairs for specific stat and card details.
        """
        fields = (('name', _('Name'),),
                  ('number', _('Number'),),)
        self._create_label_col(parent, _('Info'), fields, row=0)

        fields = (('ptime', _('Played for'),),
                  ('stime', _('Started at'),),)
        self._create_label_col(self, _('Time'), fields, row=1)

        fields = (('moves', _('Taken'),),
                  ('undo', _('Undo'),),
                  ('bookmark', _('Bookmark'),),
                  ('demo', _('Demo'),),
                  ('totalplay', _('Total for player'),),
                  ('totalgame', _('Total for game'),),
                  ('hints', _('Hints'),),)
        self._create_label_col(parent, _('Moves'), fields, row=2)

        fields = (('piles', _('Piles'),),
                  ('cards', _('Cards'),),
                  ('samerank', _('Same rank'),),)
        self._create_label_col(parent, _('Highlights'), fields, row=3)

        fields = (('rounds', _('Game round'),),
                  ('talon', _('Talon cards'),),
                  ('waste', _('Waste cards'),),
                  ('foundation', _('Foundation cards'),),)
        self._create_label_col(parent, _('Rounds / Cards'), fields, row=5)

        self.update_label_data()

    def update_label_data(self):
        """
        _update_label_data(self) -> None

        Call **self.update_label_cols** with values of stat and card details.
        """
        game = self._object
        fields = [('name', game['name'],),
                  ('number', game.random,),
                  ('ptime', game._timer,),
                  ('stime', format_time(game._timer.started),),
                 ]
        fields.extend(game.move_counter_fields.items())

        stack = game.s
        if stack['talon']:
            fields.extend([('rounds', stack['talon'].round - 1
                                         if game['redeals'] != 0 else None,),
                           ('talon', len(stack['talon'].cards),)])
        if stack['wastes']:
            fields.append(('waste', len(stack['wastes'][-1].cards),))
        if stack['foundation']:
            fields.append(('foundation', sum(len(s.cards)
                                               for s in stack['foundations']),))
        self.update_label_col(fields)


class CardsetInfoDialog(_InfoDialog):
    """
    Cardset deatils dialog.

    Creates blocks of key / value label pairs from field data within a frame.
    Pairings are stored internal for later updates which are dynamic to show
    only pairs with value data when **update** is called.
    """
    _title = _('Cardset Info')

    def body(self, parent):
        """
        body(parent:Canvas) -> None

        Create blocks of label pairs for specific cardset details.
        """
        fields = (('version', _('Version'),),
                  ('type', _('Type'),),
                  ('styles', _('Styles'),),
                  ('nations', _('Nationality'),),
                  ('year', _('Year'),),
                  ('size', _('Size'),),)
        self._create_label_col(parent, _('About cardset'), fields, row=0)

        self.update_label_data()

        self._create_image_pane(parent)

        self._create_text_pane(parent)

    def update_label_data(self):
        """
        _update_label_data(self) -> None

        Call **self.update_label_cols** with values of cardset details.
        """
        cardset = self._object.detail

        styles = nationalities = None
        if cardset['si']['styles']:
            styles = '\n'.join(CSG.STYLE[i] for i in cardset['si']['styles'])
        if cardset.si.nationalities:
            nationalities = '\n'.join(CSG.NATIONALITY[i]
                                       for i in cardset['si']['nationalities'])

        fields = (('type', CSG.TYPE[cardset['type']],),
                  ('styles', styles,),
                  ('nations', nationalities,),
                  ('year', cardset['year'] if cardset['year'] else None,),
                  ('size', '{0.width} x {0.height}'.format(cardset['size']),))
        self.update_label_col(fields)

    def _create_image_pane(self, parent):
        """
        _create_image_pane(parent:Canvas) -> None

        Create a frame with a sample face and back image from cardset.
        """
        image = self._object
        frame = ttk.Frame(parent)
        widget = ttk.Label(frame, image=image.random_face, padding=5)
        widget.grid(row=0, column=1, sticky=vcnst.ANCHOR_NE)
        widget = ttk.Label(frame, image=image.back, padding=5)
        widget.grid(row=0, column=2, sticky=vcnst.ANCHOR_NE)

    def _create_text_pane(self, parent):
        """
        _create_text_pane(parent:Canvas) -> None

        Create a frame with the contents of the COPYRIGHT file for cardset.
        """
        cardset = self._object.detail
        entry = ScrolledTextFrame(parent, bd=1, padx=5)

        with open(NJ_PATH(cardset['dir'], "COPYRIGHT")) as textfile:
            entry.config(state="normal")
            entry.insert("insert", textfile.read())
            entry.config(state="disabled")